package org.gongliang.common.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.gongliang.entity.sys.Resources;
import org.gongliang.entity.sys.User;
import org.gongliang.kit.web.SpringKit;
import org.gongliang.service.sys.ResourcesService;
import org.gongliang.service.sys.RoleService;
import org.gongliang.service.sys.UserService;

/**
 * @description：shiro权限认证
 * @author：龚亮 @date：2015/10/1 14:51
 */
public class ShiroDbRealm extends AuthorizingRealm {

	public ShiroDbRealm(org.apache.shiro.cache.CacheManager shiroCacheManager, CredentialsMatcher matcher) {
		super(shiroCacheManager, matcher);
	}

	public static void main(String[] args) {
		System.out.println(new Md5Hash("123456", "ywdev", 2).toString());
		System.out.println(new Md5Hash("123456", "", 2));
	}

	/**
	 * Shiro登录认证(原理：用户提交 用户名和密码 --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ----
	 * shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
		UserService userService = SpringKit.getBean(UserService.class);
		RoleService roleService = SpringKit.getBean(RoleService.class);
		ResourcesService resourcesService = SpringKit.getBean(ResourcesService.class);

		String username = (String) authcToken.getPrincipal();
		User userinfo = userService.findUser(username);
		// 账号不存在
		if (userinfo == null) {
			throw new UnknownAccountException("账号不存在!");
		}
		// 帐号已被锁定
		if (userinfo.getLocked()) {
			throw new DisabledAccountException("帐号已被禁用!");
		}

		ShiroUser shiroUser = new ShiroUser(userinfo);
		shiroUser.setRoles(roleService.getUserRole(userinfo.getId()));
		shiroUser.setPermissions(resourcesService.getUserPermission(userinfo.getId(), Resources.ALL));
		// 认证缓存信息
		return new SimpleAuthenticationInfo(shiroUser, userinfo.getPassword().toCharArray(), getName());
	}

	/**
	 * Shiro权限认证
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// 因为非正常退出，即没有显式调用 SecurityUtils.getSubject().logout()
		// (可能是关闭浏览器，或超时)，但此时缓存依旧存在(principals)，所以会自己跑到授权方法里。
		if (!SecurityUtils.getSubject().isAuthenticated()) {
			doClearCache(principals);
			SecurityUtils.getSubject().logout();
			return null;
		}
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();

		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setRoles(shiroUser.getStringRoles());
		info.addStringPermissions(shiroUser.getStringPermissions());

		return info;
	}

	@Override
	public void onLogout(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
		ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
		removeUserCache(shiroUser);
	}

	/**
	 * 清除用户缓存
	 * 
	 * @param shiroUser
	 */
	public void removeUserCache(ShiroUser shiroUser) {
		removeUserCache(shiroUser.getUsername());
	}

	/**
	 * 清除用户缓存
	 * 
	 * @param loginName
	 */
	public void removeUserCache(String username) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection();
		principals.add(username, super.getName());
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
	}

	@Override
	public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
		super.clearCachedAuthenticationInfo(principals);
	}

	@Override
	public void clearCache(PrincipalCollection principals) {
		super.clearCache(principals);
	}

}
